//
// Created by 29108 on 2025/7/15.
//

#ifndef RATE_LIMITER_H
#define RATE_LIMITER_H


#include <atomic>
#include <chrono>
#include <map>
#include <memory>
#include <shared_mutex>
#include <string>
#include <thread>
#include <vector>

namespace core_services {
    namespace api_gateway {
        /**
         * @brief 限流器类 - 基于令牌桶算法的API限流控制
         * @details 提供灵活的限流策略，支持按客户端ID和API路径进行限流
         *
         * 核心功能：
         * - 令牌桶算法实现平滑限流
         * - 支持突发流量处理
         * - 多维度限流（客户端、API路径）
         * - 实时统计和监控
         * - 配置热更新支持
         */
        class RateLimiter {
        public:
            /**
             * @brief 限流配置结构体
             */
            struct Config {
                int requests_per_second = 100;                    ///< 每秒允许的请求数
                int burst_size = 200;                             ///< 突发请求缓冲区大小
                std::chrono::seconds window_size{60};             ///< 统计窗口大小
                bool enable_path_based_limiting = true;           ///< 是否启用基于路径的限流
                bool enable_client_based_limiting = true;         ///< 是否启用基于客户端的限流
                std::chrono::milliseconds refill_interval{100};   ///< 令牌补充间隔

                /**
                 * @brief 从ConfigManager加载配置
                 */
                static Config fromConfigManager();

                /**
                 * @brief 验证配置有效性
                 */
                bool validate() const;
            };

            /**
             * @brief 构造函数
             * @param config 限流配置
             */
            explicit RateLimiter(const Config& config);

            /**
             * @brief 析构函数
             */
            ~RateLimiter();

            // ==================== 限流检查方法 ====================

            /**
             * @brief 检查客户端请求是否允许通过
             * @param client_id 客户端标识符
             * @return true表示允许请求，false表示被限流
             */
            bool allowRequest(const std::string& client_id);

            /**
             * @brief 检查特定API路径的请求是否允许通过
             * @param client_id 客户端标识符
             * @param api_path API路径
             * @return true表示允许请求，false表示被限流
             */
            bool allowRequest(const std::string& client_id, const std::string& api_path);

            /**
         * @brief 检查请求是否允许通过（内部实现）
         * @param client_id 客户端标识符
         * @param api_path API路径
         * @param tokens 消耗的令牌数量
         * @return true表示允许请求，false表示被限流
         */
            bool allowRequest(const std::string& client_id, const std::string& api_path, int tokens);

            /**
             * @brief 批量检查多个请求
             * @param requests 请求列表（客户端ID和API路径的对）
             * @return 每个请求的允许状态
             */
            std::vector<bool> allowRequests(const std::vector<std::pair<std::string, std::string>>& requests);

            // ==================== 统计信息 ====================

            /**
             * @brief 限流统计信息结构体
             * @details 使用原子变量确保线程安全的统计信息
             */
            struct Stats {
                std::atomic<uint64_t> total_requests{0};        ///< 总请求数
                std::atomic<uint64_t> allowed_requests{0};      ///< 允许通过的请求数
                std::atomic<uint64_t> rejected_requests{0};     ///< 被拒绝的请求数
                std::atomic<uint64_t> tokens_consumed{0};       ///< 消耗的令牌总数
                std::chrono::steady_clock::time_point last_update; ///< 最后更新时间

                /**
                 * @brief 默认构造函数
                 */
                Stats() : last_update(std::chrono::steady_clock::now()) {}

                /**
                 * @brief 拷贝构造函数（原子变量需要特殊处理）
                 * @param other 其他统计对象
                 */
                Stats(const Stats& other)
                    : total_requests(other.total_requests.load()),
                      allowed_requests(other.allowed_requests.load()),
                      rejected_requests(other.rejected_requests.load()),
                      tokens_consumed(other.tokens_consumed.load()),
                      last_update(other.last_update) {}

                /**
                 * @brief 赋值操作符
                 * @param other 其他统计对象
                 * @return 当前对象引用
                 */
                Stats& operator=(const Stats& other) {
                    if (this != &other) {
                        total_requests = other.total_requests.load();
                        allowed_requests = other.allowed_requests.load();
                        rejected_requests = other.rejected_requests.load();
                        tokens_consumed = other.tokens_consumed.load();
                        last_update = other.last_update;
                    }
                    return *this;
                }

                /**
                 * @brief 计算拒绝率
                 * @return 拒绝率（0.0-1.0）
                 */
                double getRejectionRate() const {
                    uint64_t total = total_requests.load();
                    if (total == 0) return 0.0;
                    return static_cast<double>(rejected_requests.load()) / total;
                }

                /**
                 * @brief 重置统计信息
                 */
                void reset() {
                    total_requests = 0;
                    allowed_requests = 0;
                    rejected_requests = 0;
                    tokens_consumed = 0;
                    last_update = std::chrono::steady_clock::now();
                }

                /**
                 * @brief 记录允许的请求
                 * @param token_count 消耗的令牌数
                 */
                void recordAllowed(int token_count = 1) {
                    total_requests++;
                    allowed_requests++;
                    tokens_consumed += token_count;
                    last_update = std::chrono::steady_clock::now();
                }

                /**
                 * @brief 记录被拒绝的请求
                 */
                void recordRejected() {
                    total_requests++;
                    rejected_requests++;
                    last_update = std::chrono::steady_clock::now();
                }
            };

            /**
             * @brief 获取客户端统计信息
             * @param client_id 客户端标识符
             * @return 统计信息
             */
            Stats getStats(const std::string& client_id) const;

            /**
             * @brief 获取全局统计信息
             * @return 全局统计信息
             */
            Stats getGlobalStats() const;

            /**
             * @brief 获取API路径统计信息
             * @param api_path API路径
             * @return 路径统计信息
             */
            Stats getPathStats(const std::string& api_path) const;

            /**
             * @brief 获取所有客户端的统计信息汇总
             * @return 客户端ID到统计信息的映射
             */
            std::map<std::string, Stats> getAllClientStats() const;

            /**
             * @brief 获取所有API路径的统计信息汇总
             * @return API路径到统计信息的映射
             */
            std::map<std::string, Stats> getAllPathStats() const;

            /**
             * @brief 获取限流系统的详细统计报告
             * @return 包含各种统计指标的字符串报告
             */
            std::string getStatsReport() const;

            // ==================== 配置管理 ====================

            /**
             * @brief 更新限流配置
             * @param new_config 新的配置
             */
            void updateConfig(const Config& new_config);

            /**
             * @brief 获取当前配置
             * @return 当前配置
             */
            const Config& getConfig() const { return config_; }

            /**
             * @brief 重置所有统计信息
             */
            void resetStats();

            /**
             * @brief 清理过期的令牌桶
             * @details 清理长时间未使用的令牌桶以释放内存
             */
            void cleanup();

            // ==================== 监控和诊断方法 ====================

            /**
             * @brief 获取所有客户端的令牌桶状态
             * @return 客户端ID到令牌数量的映射
             */
            std::map<std::string, int> getAllClientTokens() const;

            /**
             * @brief 获取所有路径的令牌桶状态
             * @return 路径到令牌数量的映射
             */
            std::map<std::string, int> getAllPathTokens() const;

            /**
             * @brief 获取活跃的客户端数量
             * @return 活跃客户端数量
             */
            size_t getActiveClientCount() const;

            /**
             * @brief 获取活跃的路径数量
             * @return 活跃路径数量
             */
            size_t getActivePathCount() const;

            /**
             * @brief 强制刷新所有令牌桶
             * @details 立即为所有令牌桶补充令牌
             */
            void forceRefreshAllBuckets();

            /**
             * @brief 预热令牌桶
             * @param client_id 客户端ID
             * @param path API路径
             * @details 为指定的客户端和路径预先创建令牌桶
             */
            void warmupBucket(const std::string& client_id, const std::string& path = "");

            /**
             * @brief 检查系统健康状态
             * @return 健康状态信息
             */
            std::map<std::string, std::string> getHealthStatus() const;

        private:
            Config config_;                                        ///< 限流配置

            /**
             * @brief 令牌桶结构体 - 实现令牌桶算法
             * @details 线程安全的令牌桶实现，支持平滑的流量控制
             */
            struct TokenBucket {
                std::atomic<int> tokens;                           ///< 当前令牌数量（原子操作）
                std::chrono::steady_clock::time_point last_refill; ///< 最后补充令牌时间
                Stats stats;                                       ///< 统计信息
                mutable std::mutex mutex_;                         ///< 保护令牌桶操作的互斥锁
                std::chrono::steady_clock::time_point created_time; ///< 创建时间
                std::chrono::steady_clock::time_point last_access_time; ///< 最后访问时间

                /**
                 * @brief 构造函数
                 * @param initial_tokens 初始令牌数量
                 */
                explicit TokenBucket(int initial_tokens = 0)
                    : tokens(initial_tokens),
                      last_refill(std::chrono::steady_clock::now()),
                      created_time(std::chrono::steady_clock::now()),
                      last_access_time(std::chrono::steady_clock::now()) {}

                /**
                 * @brief 拷贝构造函数
                 * @param other 其他令牌桶
                 */
                TokenBucket(const TokenBucket& other)
                    : tokens(other.tokens.load()),
                      last_refill(other.last_refill),
                      stats(other.stats),
                      created_time(other.created_time),
                      last_access_time(other.last_access_time) {}

                /**
                 * @brief 赋值操作符
                 * @param other 其他令牌桶
                 * @return 当前对象引用
                 */
                TokenBucket& operator=(const TokenBucket& other) {
                    if (this != &other) {
                        std::lock_guard<std::mutex> lock(mutex_);
                        tokens = other.tokens.load();
                        last_refill = other.last_refill;
                        stats = other.stats;
                        created_time = other.created_time;
                        last_access_time = other.last_access_time;
                    }
                    return *this;
                }

                /**
                 * @brief 尝试消费令牌
                 * @param count 需要消费的令牌数量
                 * @param config 限流配置
                 * @return true表示成功消费，false表示令牌不足
                 * @details 线程安全的令牌消费，自动进行令牌补充
                 */
                bool tryConsume(int count, const Config& config);

                /**
                 * @brief 补充令牌
                 * @param config 限流配置
                 * @details 根据时间间隔和配置的速率补充令牌
                 */
                void refill(const Config& config);

                /**
                 * @brief 获取当前令牌数量
                 * @return 当前令牌数量
                 */
                int getCurrentTokens() const {
                    return tokens.load();
                }

                /**
                 * @brief 检查令牌桶是否空闲超时
                 * @param timeout 超时时间
                 * @return true表示已超时
                 */
                bool isIdleTimeout(std::chrono::minutes timeout) const {
                    auto now = std::chrono::steady_clock::now();
                    return (now - last_access_time) > timeout;
                }

                /**
                 * @brief 更新最后访问时间
                 */
                void updateAccessTime() {
                    last_access_time = std::chrono::steady_clock::now();
                }
            };

            // 客户端令牌桶映射
            std::map<std::string, TokenBucket> client_buckets_;
            // API路径令牌桶映射
            std::map<std::string, TokenBucket> path_buckets_;
            // 全局统计信息
            Stats global_stats_;

            // 线程安全保护
            mutable std::shared_mutex buckets_mutex_;

            // 清理任务相关
            std::atomic<bool> cleanup_running_{false};        ///< 清理任务运行状态
            std::thread cleanup_thread_;                      ///< 清理线程

            // ==================== 私有辅助方法 ====================

            /**
             * @brief 获取或创建客户端令牌桶
             * @param client_id 客户端ID
             * @return 令牌桶引用
             */
            TokenBucket& getOrCreateClientBucket(const std::string& client_id);

            /**
             * @brief 获取或创建路径令牌桶
             * @param path API路径
             * @return 令牌桶引用
             */
            TokenBucket& getOrCreatePathBucket(const std::string& path);

            /**
             * @brief 启动清理任务
             */
            void startCleanupTask();

            /**
             * @brief 停止清理任务
             */
            void stopCleanupTask();

            /**
             * @brief 清理任务主循环
             */
            void cleanupTaskLoop();

            /**
             * @brief 验证请求参数
             * @param client_id 客户端ID
             * @param path API路径
             * @param tokens 令牌数量
             * @return 是否有效
             */
            bool validateRequest(const std::string& client_id,
                               const std::string& path,
                               int tokens) const;

            /**
             * @brief 记录请求统计信息
             * @param bucket 令牌桶
             * @param allowed 是否允许
             * @param token_count 令牌数量
             */
            void recordStats(TokenBucket& bucket, bool allowed, int token_count = 1);

            /**
             * @brief 获取令牌桶的键名
             * @param client_id 客户端ID
             * @param path API路径
             * @return 键名
             */
            std::string getBucketKey(const std::string& client_id, const std::string& path) const;

            // 统计信息保护锁
            mutable std::shared_mutex stats_mutex_;

            // 清理任务配置
            std::chrono::milliseconds cleanup_interval_{std::chrono::minutes(5)};  ///< 清理任务执行间隔

            /**
             * @brief 清理线程工作函数
             */
            void cleanupWorker();

            /**
             * @brief 更新全局统计信息
             * @param allowed 是否允许请求
             * @param token_count 令牌数量
             */
            void updateGlobalStats(bool allowed, int token_count = 1);
        };

    }
}



#endif //RATE_LIMITER_H
